Diamanten#

Der folgende Datensatz enthält die Preise und Eigenschaften von Diamanten. Die Eigenschaften sind:

  • Preis (in US-Dollar)

  • Karatgewicht des Diamanten

  • Schliffqualität (befriedigend, gut, sehr gut, erstklassig, ideal)

  • Farbe des Diamanten (von J (schlechteste) bis D (beste))

  • Reinheit - ein Maß für die Klarheit des Diamanten (I1 (schlechteste), SI2, SI1, VS2, VS1, VVS2, VVS1, IF (beste))

  • x - Länge in mm

  • y - Breite in mm

  • z - Tiefe in mm

  • Gesamttiefe (in Prozent = z / Mittelwert (x, y) = 2 * z / (x + y))

  • Breite der Oberseite des Diamanten im Verhältnis zur breitesten Stelle

import pandas as pd 

data = pd.read_csv('data/diamonds_DE.csv', skiprows=2)
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 53940 entries, 0 to 53939
Data columns (total 11 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   Unnamed: 0        53940 non-null  int64  
 1   Karat             53940 non-null  float64
 2   Schliffqualitaet  53940 non-null  object 
 3   Farbe             53940 non-null  object 
 4   Reinheit          53940 non-null  object 
 5   Tiefe             53940 non-null  float64
 6   Breite            53940 non-null  float64
 7   Preis             53940 non-null  int64  
 8   x                 53940 non-null  float64
 9   y                 53940 non-null  float64
 10  z                 53940 non-null  float64
dtypes: float64(6), int64(2), object(3)
memory usage: 4.5+ MB

Der Datensatz enthält 53940 Einträge mit 11 Eigenschaften. Alle Einträge sind gültige Einträge. Die Eigenschaften ‘Unnamed: 0’ und ‘Preis’ sind Integers. Die Eigenschaften ‘Karat’, ‘Tiefe’, ‘Breite’, ‘x’, ‘y’ und ‘z’ sind Floats. Die Eigenschaften ‘Schliffqualitaet’, ‘Farbe’ und ‘Reinheit’ sind Objekte.

data.head()
Unnamed: 0 Karat Schliffqualitaet Farbe Reinheit Tiefe Breite Preis x y z
0 1 0.23 ideal E SI2 61.5 55.0 326 3.95 3.98 2.43
1 2 0.21 erstklassig E SI1 59.8 61.0 326 3.89 3.84 2.31
2 3 0.23 gut E VS1 56.9 65.0 327 4.05 4.07 2.31
3 4 0.29 erstklassig I VS2 62.4 58.0 334 4.20 4.23 2.63
4 5 0.31 gut J SI2 63.3 58.0 335 4.34 4.35 2.75

Die ersten fünf Zeilen des Datensatzes legen nahe, dass die Eigenschaft ‘Unnamed: 0’ ein Index ist. Wir visualisieren diese Eigeschaft, um die Hypothese zu überprüfen.

import plotly.express as px

fig = px.scatter(data, y = 'Unnamed: 0',
                 title='Diamanten')
fig.show()

Tatsächlich stimmen (zumindest visuell) der automatisch erzeugte Index des DataFrame-Objektes und die Werte von ‘Unnamed: 0’ überein. Die überflüssige Spalte wird gelöscht.

data.drop(columns='Unnamed: 0', inplace=True)
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 53940 entries, 0 to 53939
Data columns (total 10 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   Karat             53940 non-null  float64
 1   Schliffqualitaet  53940 non-null  object 
 2   Farbe             53940 non-null  object 
 3   Reinheit          53940 non-null  object 
 4   Tiefe             53940 non-null  float64
 5   Breite            53940 non-null  float64
 6   Preis             53940 non-null  int64  
 7   x                 53940 non-null  float64
 8   y                 53940 non-null  float64
 9   z                 53940 non-null  float64
dtypes: float64(6), int64(1), object(3)
memory usage: 4.1+ MB

Als nächstes werden die Eigenschaften weiter analysiert. Um einfacher auf die Input-Eigenschaften zugreifen zu können, definieren wir zwei Listen. Die erste Liste enthält die numerischen Input-Eigenschaften, die zweite die kategorischen Input-Eigenschaften. Die Zielgröße, d.h. der Output, ist die Eigenschaft Preis.

input_numerical = ['Karat', 'Tiefe', 'Breite', 'x', 'y', 'z']
input_categorial = ['Schliffqualitaet', 'Farbe', 'Reinheit']

Die Übersicht der statistischen Kennzahlen zu den numerischen Input-Eigenschaften ist wie folgt:

data.describe()
Karat Tiefe Breite Preis x y z
count 53940.000000 53940.000000 53940.000000 53940.000000 53940.000000 53940.000000 53940.000000
mean 0.797940 61.749405 57.457184 3932.799722 5.731157 5.734526 3.538734
std 0.474011 1.432621 2.234491 3989.439738 1.121761 1.142135 0.705699
min 0.200000 43.000000 43.000000 326.000000 0.000000 0.000000 0.000000
25% 0.400000 61.000000 56.000000 950.000000 4.710000 4.720000 2.910000
50% 0.700000 61.800000 57.000000 2401.000000 5.700000 5.710000 3.530000
75% 1.040000 62.500000 59.000000 5324.250000 6.540000 6.540000 4.040000
max 5.010000 79.000000 95.000000 18823.000000 10.740000 58.900000 31.800000
fig = px.box(data, y = input_numerical,
             title='Diamanten: numerische Eigenschaften',
             labels={'variable': 'Eigenschaft', 'value': 'Wert'})
fig.show()

Die Eigenschaft Karat unterscheidet sich in der Größenordnung von den beiden Eigenschaften Tiefe und Breite sowie x, y, und z. Diese drei Gruppen werden jetzt einzeln untersucht.

fig = px.box(data, y = 'Karat',
             title='Diamanten')
fig.show()

75 % der Diamanten haben ein Karat und weniger, wobei der Median bei 0.7 Karat liegt. Das ist etwas niedriger als der Mittelwert von 0.8 Karat. Der höhere Mittelwert wird sicherlich bedingt durch die vielen Ausreißer nach oben ab 2 bis ca. 5 Karat.

Als nächstes werden Tiefe und Breite untersucht.

fig = px.box(data, y = ['Tiefe', 'Breite'],
             title='Diamanten: numerische Eigenschaften',
             labels={'variable': 'Eigenschaft', 'value': 'Größe'})
fig.show()

50 % aller Diamanten haben eine Tiefe zwischen 61 % und 62 %. Der Median ist mit 61.8 % mittwig zwischen Q1 und Q3 und stimmt mit dem Mittelwert 61.7 % überein. Es gibt Ausreißer nach oben und unten.

Bei der Breite ist der Median 57 näher am Q1-Wert 56 und und liegt auch etwas unterhalb des Mittelwertes von 57.4.

fig = px.box(data, y = ['x', 'y', 'z'],
             title='Diamanten: numerische Eigescnhaften',
             labels={'variable': 'Eigenschaft', 'value': 'Wert'})
fig.show()

Der Boxplot sowie die statistischen Kennzahlen der Eigenschaften x, y und z zeigen Ungereimtheiten. Bei allen drei Eigenschaften wird auch der Wert Null angenommen. Das ist unmöglich, daher müssen diese Diamanten aus dem Datensatz entfernt werden.

Darüber hinaus gibt es bei der Größe in y-Richtung zwei deutliche Ausreißer mit 31.8 mm und 58.9 mm. Auch bei der Größe in z-Richtung gibt es einen deutlichen Ausreißer nach oben mit z = 31.8 mm. Diese Diamanten werden ebenfalls entfernt.

data.drop(data[ data['x'] == 0 ].index, inplace=True)
data.drop(data[ data['y'] == 0 ].index, inplace=True)
data.drop(data[ data['z'] == 0 ].index, inplace=True)
data.drop(data[ data['y'] > 31.0 ].index, inplace=True)
data.drop(data[ data['z'] > 31.0 ].index, inplace=True)
data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 53917 entries, 0 to 53939
Data columns (total 10 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   Karat             53917 non-null  float64
 1   Schliffqualitaet  53917 non-null  object 
 2   Farbe             53917 non-null  object 
 3   Reinheit          53917 non-null  object 
 4   Tiefe             53917 non-null  float64
 5   Breite            53917 non-null  float64
 6   Preis             53917 non-null  int64  
 7   x                 53917 non-null  float64
 8   y                 53917 non-null  float64
 9   z                 53917 non-null  float64
dtypes: float64(6), int64(1), object(3)
memory usage: 4.5+ MB

Somit sind es nur 53917 Einträge von ehemals 53940 Einträgen. Es wurden 23 Diamanten entfernt.

Als nächstes betrachten wir die kategorischen Eigenschaften.

for category in input_categorial:
    print(f'Eigenschaft {category}: {data[category].unique()}')
Eigenschaft Schliffqualitaet: ['ideal' 'erstklassig' 'gut' 'sehr gut' 'fair']
Eigenschaft Farbe: ['E' 'I' 'J' 'H' 'F' 'G' 'D']
Eigenschaft Reinheit: ['SI2' 'SI1' 'VS1' 'VS2' 'VVS2' 'VVS1' 'I1' 'IF']